﻿using Sgr.DataCategories.Domain.AdministrativeDivisions;
using Sgr.DataCategories.Services;
using Sgr.Domain.Entities;
using Sgr.Domain.Managers;
using Sgr.Exceptions;
using Sgr.Generator;
using System.Reflection.Emit;
using System.Threading;
using System.Threading.Tasks;

namespace Sgr.DataCategories.Domain.DataCategoryItem
{
    public class DataCategoryItemManage : TreeNodeManageBase<DataCategoryItem, long>, IDataCategoryItemManage
    {
        private readonly ISegmentNumIdGenerator _numberIdGenerator;
        private readonly ICategoryTypeService _categoryTypeService;

        // 添加一个属性来安全地转换基类的仓储引用
        private IDataCategoryItemRepository DataCategoryItemRepository =>
            (IDataCategoryItemRepository)_repository;

        public DataCategoryItemManage(IDataCategoryItemRepository repository,
            ISegmentNumIdGenerator numberIdGenerator,
            ICategoryTypeService categoryTypeService)
            : base(repository)
        {
            _numberIdGenerator = numberIdGenerator ?? throw new ArgumentNullException(nameof(numberIdGenerator));
            _categoryTypeService = categoryTypeService ?? throw new ArgumentNullException(nameof(categoryTypeService));
        }

        public virtual async Task<DataCategoryItem> CreateNewAsync(
            string name,
            string value,
            string? remarks,
            string categoryTypeCode,
            int orderNumber,
            bool isEditable = true,
            long? parentId = null,
            CancellationToken cancellationToken = default)
        {
            // 验证字典分类是否存在
            _ = await _categoryTypeService.GetAsync(categoryTypeCode) ?? throw DomainException.ValidationError($"数据字典分类{categoryTypeCode}未定义");

            // 检查字典编码是否唯一
            if (!await IsValueUniqueAsync(value, categoryTypeCode, null, cancellationToken))
                throw DomainException.ValidationError($"字典编码{value}已存在");

            // 获取Id
            var id = await _numberIdGenerator.GetUniqueIdAsync("", cancellationToken);

            // 处理父级节点
            parentId ??= 0;

            DataCategoryItem? parentNode = null;
            if (parentId > 0)
            {
                parentNode = await _repository.GetAsync(parentId.Value, cancellationToken);
                if (parentNode == null)
                    throw DomainException.ValidationError($"上级节点ID {parentId} 不存在");
            }
            string nodePath = GetNodePath(parentNode, id, 5);

            //返回

            // 创建数据字典项
            var entity = new DataCategoryItem(
                categoryTypeCode,
                name,
                value,
                isEditable,
                orderNumber,
                remarks)
            {
                Id = id,
            };

            entity.SetParent(parentId.Value, nodePath);

            return entity;
        }

        /// <summary>
        /// 检查字典项值是否唯一
        /// </summary>
        /// <param name="value">字典项值</param>
        /// <param name="categoryTypeCode">字典分类编码</param>
        /// <param name="excludeId">需要排除的ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>值是否唯一</returns>
        public async Task<bool> IsValueUniqueAsync(
            string value,
            string categoryTypeCode,
            long? excludeId = null,
            CancellationToken cancellationToken = default)
        {
            // 参数验证
            Check.StringNotNullOrEmpty(value, nameof(value));
            Check.StringNotNullOrEmpty(categoryTypeCode, nameof(categoryTypeCode));

            return await DataCategoryItemRepository.ValueIsUniqueInCategoryAsync(
                value,
                categoryTypeCode,
                excludeId,
                cancellationToken);
        }

        protected override void BeforeDeleteEntity(DataCategoryItem entity)
        {
            base.BeforeDeleteEntity(entity);

            // 标记删除前检查实体是否可编辑
            if (!entity.IsEditable)
                throw DomainException.ValidationError("系统预置的数据字典项不允许删除");

            entity.MarkForDeletion();
        }

        protected override void ChangeEntityParent(DataCategoryItem entity, DataCategoryItem? parentEntity, int maxLevel = 10)
        {
            long parentId = 0;
            if (parentEntity != null)
                parentId = parentEntity!.Id;

            string path = GetNodePath(parentEntity, entity.Id, maxLevel);

            entity.SetParent(parentId, path);
        }
    }
}